iT邦幫忙

2021 iThome 鐵人賽

DAY 3
0
自我挑戰組

Java SE系列 第 3

Day03:小姐,妳手上那是什麼?

  • 分享至 

  • xImage
  •  

昨天提到了一個奇怪的現象:

byte num = 128;

如上撰寫,妳的IDE將會在128底下亮出紅線,並說:「Type mismatch: cannot convert from int to byte」

今天就會來探討一下為什麼會發生這個奇怪的現象,不過在進入正題之前,想先談談何謂字面常量(literal constant)

昨天談到了基本型別(primitive type),其實被宣告為基本型別的變數所儲存的值就是各種字面常量,字面常量本身就代表了最純粹的數值,沒有經過記憶體位址的包裝,1就是1,2就是2。不過字面常量就只有我們日常生活使用的十進位(decimal)數字嗎?當然不止,還有十六進位(hexadecimal)、八進位(octet)、二進位(binary):

  • 十進位:10
  • 十六進位:0xA
  • 八進位:012
  • 二進位:0b1010

以上這些都是可以在Java程式中表達的字面常量,而且也都等於我們所謂的10這個數值。

欸,那還有一個字元(char)勒? 它是怎麼被儲存的? 電腦真的會存進abcd嗎?
實際上在Java,字元骨子裡是一個16 bits範圍的正數值,每個數值會再透過轉換轉成我們所看到的文字,所以當我們如下指派時:

int num = 'A';

num會變成65的int數值(JLS5.1.2),神奇吧。所以字元就像是一個蘿蔔一個坑,每個數字會代表一個文字,再查表對應出代表的文字(Unicode Table)

最後提點一下,昨天雖然有提到String字串不是基本型別,可是妳應該有注意到我們指派給String型別變數的也是像字面常量的值,其實沒錯!我們在等號右邊給它的字串也是一種字面常量,但字串比較特別一點,之後有機會再討論。

好了,該進入正題了~ 到底為什麼JVM要說我們給byte變數一個int字面常量勒?
答案就是,就是這樣...沒有為什麼,這就是Java在字面常量上的潛規則,只要我們直接打出數字的數值,它預設就是int的型態。而之所以byte num = 127會可以編譯成功是因為Java有自動針對byte, short, char, int常數narrowing conversion的功能(JLS5.2)

整數的常量會自動視為int型態,浮點數呢? 浮點數則是自動視為double型態,所以以下會編譯不過哦:

float fNum = 1.5;

可是我就是想要存1.5到float型別的變數怎麼辦? 這時候就有2種辦法了:

float fNum01 = 1.5f;
float fNum02 = (float)1.5;

第一種辦法是從字面常量下手,如果我們希望表示出float型態的浮點數,就得在最後面加上一個"f";
第二種辦法是使用Java的轉型(cast)語法,在值的前面用括號包住我們想轉成的型別名稱,就可以強制轉過去了。這個轉型水也是有點深度...之後可能需要花點篇幅說明,因為並不是可以無腦轉型的,尤其之後又有非基本型別的狀況時。

其實在整數也會有這樣的情況,由於數字預設是int型別,那如果我們寫下了一個超出int型別範圍的數值,並預計用一個long型別的變數來裝,要怎麼做到勒? 答案就是:

long num = 2147483648L;

在整數數值的最後面加上"L",就會把常量轉換為long型態了。

好了,我們只剩最後一個部分要講了,就是運算時常量的潛規則。

byte n1 = 1;
byte n2 = 2;
byte n3 = n1 + n2;

以上程式碼在第三行會出錯,詭異吧。這是因為Java預設在進行運算時,若運算元是小於int的型別,會先自動轉化為int型別後,再進行運算。所以只要有加減乘除的運算,最後結果一定最小會是int的型別!那下面的話呢:

int n1 = 1;
long n2 = 2;
int n3 = n1 + n2;

這樣的話第三行也還是最出錯,因為現在最大的型別變成long了,這時Java會先把所有型別都提升到long,再進行運算。這種特性稱為自動提升(promote)。
最後來個逗趣的東西:

int nn = 1 + 'A';

試試看nn會等於多少吧。

這篇有點長,來做個小結:

  1. 數字的字面常量除了十進位,也可以用十六進位(0x)、八進位(0)、二進位(0b)來寫出數值
  2. 字元char骨子裡其實是一個16 bits的數字,再透過查表將數字轉換為文字
  3. 整數字面常量預設為int型別,若需要表達long型別的數值常量,要在最後面加上"L"
  4. 浮點數字面常量預設為double型別,若需要表達float型別的數值常量,要在最後面加上"f"
  5. 進行運算時會自動將運算元提升到int型別; 若有大於int型別的運算元則會以最大的型別為基準進行運算

天啊我把Java講得好複雜哈哈,而且根本還沒進到物件@@


上一篇
Day02:先生先生,請問你裝了什麼進去?
下一篇
Day04:原來早就在這裡有共享經濟了
系列文
Java SE30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言